<?php


namespace app\task\job;

use app\common\service\redis\PoolRedis;
use app\model\AdminDormitory;
use app\model\AdminStaff;
use app\model\AdminStaffIcCard;
use app\model\AdminStaffIcCardPool;
use app\model\AdminStaffPhonePool;
use app\model\AdminStudentDormitory;
use app\model\AdminSuperSim;
use app\model\AdminTeachingBuilding;
use app\util\Strs;
use app\util\Tools;
use app\validate\AdminBuilding;
use app\validate\AdminClassroom;
use app\validate\AdminIcCard;
use app\validate\AdminIcCardPool;
use app\validate\AdminPhonePool;
use think\exception\ValidateException;
use think\facade\Log;
use think\queue\Job;

class UploadSyncHandlerJob
{
    /**
     * 队列入口
     * @param Job $job
     * @param $data
     */
    public function fire(Job $job, $data)
    {
        $isJobDone = $this->handle($data);
        if ($isJobDone) {
            //如果任务执行成功，记得删除任务
            $job->delete();
        }else{
            //通过这个方法可以检查这个任务已经重试了几次了
            if ($job->attempts() > 3){
                $job->delete();
            }
        }
    }

    /**
     * 处理
     * @param $data
     * @return bool
     * @desc 上传文件统一处理
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function handle($data)
    {
        $redis = PoolRedis::instance();

        $model = $data['model'];
        $action = $data['action'];

        while ($datum = $redis->rPop($action)) {
            $datum = unserialize($datum);
            try {
                if ($action == 'upload_super_sim') { // 超级sim卡
                    $this->saveSimCard($action, $datum, $redis);
                    continue;
                }
                if ($action == 'upload_ic_card') {  // ic card
                    $this->saveIcCard($action, $datum, $redis);
                    continue;
                }

                if ($action == 'upload_ic_card_pool') { // ic card pool
                    $this->modelValidate($datum, AdminIcCardPool::class);
                }

                if ($action == 'upload_phone_pool') { // phone pool
                    $this->savePhonePool($action, $datum, $redis);
                    continue;
                }

                if (in_array($action, ['upload_student', 'upload_staff'])) { // 学生、职工信息
                    $this->saveStaffUnionData($datum);
                    continue;
                }

                if ($action == 'upload_student_dormitory') { // 宿舍号信息
                    $this->getDormitoryID($datum);
                    $this->modelValidate($datum, \app\validate\AdminStudentDormitory::class);
                }

                // 上传教室
                if ($action == 'upload_classroom') {    // 教室信息
                    $this->getBuildingId($datum);
                    $this->modelValidate($datum, AdminClassroom::class);
                }

                if ($action == 'upload_teaching_building') { // 教学楼
                    $this->modelValidate($datum, AdminBuilding::class);
                }

                if ($action == 'upload_dormitory') { // 宿舍楼信息
                    $this->modelValidate($datum, \app\validate\AdminDormitory::class);
                }

                $model::create($datum);
            } catch (\Exception $e) {
                $redis->lPush($action."_error", serialize(['error_msg' => $e->getMessage(), 'data' => $datum]));
                Log::error("{$action}-exception: ".$e->getMessage());
                Log::error($e->getTraceAsString());
            }
        }
        return true;
    }

    // 导入学生、职工。staff关联宿舍、sim卡、ic卡保存
    private function saveStaffUnionData($datum)
    {
        try {
            $smart_card = $datum['ic_card'];
            unset($datum['ic_card']);

            $where = [
                'school_id' => $datum['school_id'],
                'is_delete' => 0
            ];
            if ($datum['phone']) {
                $where['phone'] = $datum['phone'];
            } elseif ($datum['student_no']) {
                $where['student_no'] = $datum['student_no'];
            } else {
                throw new \Exception('学号和手机号不能都为空');
            }
            if (!$datum['student_dormitory_id']) {
                throw new \Exception('宿舍号不能都为空');
            }
            $staff = AdminStaff::where($where)->find();
            if (!$staff) {
                // 不存在创建学生
                $insert = $datum;
                unset($insert['student_dormitory_id']);
                $staff = $this->createStaff($insert);
            } elseif ($staff->type == AdminStaff::STUDENT) {
                // 存在学生更新信息
                $staff->student_no = $datum['student_no'];
                $staff->phone = $datum['phone'];
                $staff->name = $datum['name'];
                $staff->major = $datum['major'];
                $staff->id_card = $datum['id_card'];
                $staff->sex = $datum['sex'];
                $staff->entrance_time = $datum['entrance_time'];
                $staff->graduate_time = $datum['graduate_time'];

                // 学生IC卡只有一张，为和职工保持一致，也保存为一对多格式
                if ($smart_card && !$staff->smart_card) {
                    $staff->smart_card = $smart_card;
                } else {
                    $smart_card = $staff->smart_card;
                }
                $staff->save();
            }
            $lock_permission = [];
            if ($datum['blue_booth_rule']) $lock_permission[] = 1;
            if ($datum['temp_pwd_rule']) $lock_permission[] = 2;
            if ($datum['super_sim_rule']) $lock_permission[] = 3;
            if ($datum['ic_card_rule']) $lock_permission[] = 4;
            $lock_permission = implode(",", $lock_permission);

            // 找出一条
            $icCard = AdminStaffIcCard::where([
                'school_id' => $datum['school_id'],
                'student_dormitory_id' => $datum['student_dormitory_id'],
                'staff_id' => $staff->id,
                'is_delete' => 0
            ])->find();
            if ($icCard) {
                $icCard->lock_permission = $lock_permission;
                if ($smart_card) $icCard->ic_card = $smart_card;
                $icCard->save();
            } else {
                $data = [
                    'school_id' => $datum['school_id'],
                    'dormitory_id' => $this->getDormitoryIDByStuId($datum['student_dormitory_id']),
                    'student_dormitory_id' => $datum['student_dormitory_id'],
                    'staff_id' => $staff->id,
                    'ic_card' => $smart_card,
                    'lock_permission' => $lock_permission,
                ];
                $this->modelValidate($data, AdminIcCard::class);
                AdminStaffIcCard::create($data);
            }
        } catch (\Exception $e) {
            throw new \Exception($e->getMessage());
        }
    }

    // sim卡ID导入
    private function saveSimCard($action, $datum, $redis)
    {
        $datum['phone'] = trim($datum['phone']);
        $datum['ic_card'] = trim($datum['ic_card']);
        if (!isset($datum['phone'])) {
            //$redis->lPush($action."_error", serialize(['error_msg' => '手机号不存在', 'data' => $datum]));
            return;
        }
        if (!$datum['sim_card']) {
            $redis->lPush($action."_error", serialize(['error_msg' => 'SIM卡ID不能未空', 'data' => $datum]));
            return;
        }
        try {
            $staff = AdminStaff::where([
                'school_id' => $datum['school_id'],
                'phone' => $datum['phone'],
                'is_delete' => 0
            ])->find();
            // 去除 不存在学生或职工信息则创建
            if (!$staff) {
                $insert = $datum;
                unset($insert['student_dormitory_id']);
                // $staff = $this->createStaff($insert);
                $redis->lPush($action."_error", serialize(['error_msg' => '学生或职工信息不存在->'.$datum['phone'], 'data' => $datum]));
                return;
            }
            $where = [
                'staff_id' => $staff->id,
                'school_id' => $datum['school_id'],
                'is_delete' => 0
            ];
            $staff->sim_card = $datum['sim_card'];
            $staff->save();
            AdminStaffIcCard::update(['sin_uid' => $datum['sim_card']], $where);

            $redis = PoolRedis::instance();
            $redis->hSetNx("smartCards", $datum['sim_card'], $staff->id);
        } catch (\Exception $e) {
            throw new \Exception($e->getMessage());
        }
        return;
    }
    // ic卡导入
    private function saveIcCard($action, $datum, $redis)
    {
        $datum['phone'] = trim($datum['phone']);
        $datum['ic_card'] = trim($datum['ic_card']);
        if (!isset($datum['phone'])) {
            //$redis->lPush($action."_error", serialize(['error_msg' => '手机号不存在', 'data' => $datum]));
            return;
        }
        if (!$datum['ic_card']) {
            $redis->lPush($action."_error", serialize(['error_msg' => 'IC卡ID不能未空', 'data' => $datum]));
            return;
        }
        try {
            $staff = AdminStaff::where([
                'school_id' => $datum['school_id'],
                'phone' => $datum['phone'],
                'is_delete' => 0
            ])->find();
            // 去除 不存在学生或职工信息则创建
            if (!$staff) {
                $insert = $datum;
                unset($insert['student_dormitory_id']);
                // $staff = $this->createStaff($insert);
                $redis->lPush($action."_error", serialize(['error_msg' => '学生或职工信息不存在->'.$datum['phone'], 'data' => $datum]));
                return;
            }
            $where = [
                'staff_id' => $staff->id,
                'school_id' => $datum['school_id'],
                'is_delete' => 0
            ];
            $staff->smart_card = $datum['ic_card'];
            $staff->save();
            // 非学生的则更新具体宿舍IC卡
            if ($staff->type != AdminStaff::STUDENT) {
                $where['student_dormitory_id'] = $datum['student_dormitory_id'];
            }
            AdminStaffIcCard::update(['ic_card' => $datum['ic_card']], $where);
            $redis = PoolRedis::instance();
            $redis->hSetNx("smartCards", $datum['ic_card'], $staff->id);
        } catch (\Exception $e) {
            throw new \Exception($e->getMessage());
        }
        return;
    }

    // 创建学生、职工
    private function createStaff($datum)
    {
        $datum['status'] = AdminStaff::AUDIT_PASS;
        $datum['uuid'] = substr(Strs::uuid(), 1, -1);
        $str = $datum['phone'] ?? ($datum['id_card'] ?? '12345678');
        $datum['password'] = substr($str, -6);
        $scene = !isset($datum['type']) || $datum['type'] == AdminStaff::STUDENT ? 'student' : 'staff';
        try {
            validate(\app\validate\AdminStaff::class)->scene($scene)->check($datum);
        } catch (ValidateException $e) {
            throw new \Exception($e->getError());
        }
        $datum['password'] = Tools::userMd5($datum['password']);
        $staff = AdminStaff::create($datum);
        return $staff;
    }

    // 手机号池导入
    private function savePhonePool($action, $datum, $redis)
    {
        $datum['phone'] = trim($datum['phone']);
        $datum['uid'] = trim($datum['uid']);
        try {
            $phonePool = AdminStaffPhonePool::where('phone','=',$datum['phone'])->find();
            if ($phonePool){
                $redis->lPush($action."_error", serialize(['error_msg' => '手机号已存在', 'data' => $datum]));
                return;
            }
            AdminStaffPhonePool::create($datum);
        } catch (\Exception $e) {
            throw new \Exception($e->getMessage());
        }
        return;
    }

    // 获取宿舍楼ID
    private function getDormitoryID(&$data)
    {
        $id = AdminDormitory::where([
            'school_id' => $data['school_id'],
            'name' => $data['dormitory'],
            'is_delete' => 0
        ])->value('id');
        if (!$id) {
            $temp = $data;
            $temp['name'] = $data['dormitory'];

            $this->modelValidate($temp, \app\validate\AdminDormitory::class);
            $res = AdminDormitory::create($temp);
            $id = $res->id;
        }
        $data['dormitory_id'] = $id;
    }

    // 通过宿舍号ID获取楼栋ID
    private function getDormitoryIDByStuId($stuId)
    {
        $id = AdminStudentDormitory::where([
            'id' => $stuId,
            'is_delete' => 0
        ])->value('dormitory_id');
        if (!$id) {
            throw new \Exception("宿舍号【{$stuId}】不存在或已删除");
        }
        return $id;
    }

    // 通过学校ID和教学楼名称获取教学楼ID
    private function getBuildingId(&$item)
    {
        $building_id = AdminTeachingBuilding::where([
            'school_id' => $item['school_id'],
            'name' => $item['building_name'],
            'is_delete' => 0
        ])->value('id');
        if (!$building_id) {
            $temp = [
                'school_id' => $item['school_id'],
                'name' => $item['building_name']
            ];

            $this->modelValidate($temp, AdminBuilding::class);
            $building = AdminTeachingBuilding::create();
            $building_id = $building->id;
        }
        $item['building_id'] = $building_id;
    }

    // 数据库验证
    private function modelValidate($data, $class)
    {
        try {
            validate($class)->check($data);
        } catch (ValidateException $e) {
            throw new \Exception($e->getError());
        }
    }
}
